package com.hardson.toolkit.util;

import lombok.Cleanup;
import org.apache.commons.io.IOUtils;
import org.apache.tools.zip.ZipFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Enumeration;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class ZipUtil {
    /**
     * 压缩文件
     *
     * @param zipFileName 保存的压缩包文件路径
     * @param inputDir    需要压缩的文件夹或者文件路径
     * @throws IOException IO异常
     */
    public static void zip(final String zipFileName, final String inputDir) throws IOException {
        zip(zipFileName, new File(inputDir));
    }

    /**
     * 压缩
     *
     * @param zipFileName 压缩文件名
     * @param inputDir    要压缩的文件夹
     * @throws IOException IO异常
     */
    public static void zip(final String zipFileName, final File inputDir) throws IOException {
        String encoding = "GBK";// System.getProperty("sun.jnu.encoding");// 为解决中文文件名乱码问题
        try (ZipOutputStream out = new ZipOutputStream(Files.newOutputStream(Paths.get(zipFileName)),
                Charset.forName(encoding))) {
            out.setLevel(Deflater.NO_COMPRESSION);
            zip(out, inputDir, "");
        }
    }

    /**
     * 递归压缩方法
     *
     * @param out  压缩包输出流
     * @param file 需要压缩的文件
     * @param base 压缩的路径
     * @throws IOException IO异常
     */
    public static void zip(final ZipOutputStream out, final File file, String base) throws IOException {
        if (file.isDirectory()) { // 如果是文件夹，则获取下面的所有文件
            File[] files = file.listFiles();
            if (files == null) {
                return;
            }
            out.putNextEntry(new ZipEntry(base + "/"));
            base = base.length() == 0 ? "" : base + "/";
            for (File subFile : files) {
                zip(out, subFile, base + subFile.getName());
            }
        } else { // 如果是文件，则压缩
            out.putNextEntry(new ZipEntry(base)); // 生成下一个压缩节点
            try (InputStream in = IOUtils.buffer(Files.newInputStream(file.toPath()))) {
                IOUtils.copy(in, out, 4096);
            }
        }
    }

    public static void extZipFileList(final String zipFileName, final String extPlace) throws IOException {
        try (ZipInputStream in = new ZipInputStream(Files.newInputStream(Paths.get(zipFileName)))) {
            extZipFileList(in, extPlace);
        }
    }

    public static void extZipFileList(final File file, final String extPlace) throws IOException {
        try (ZipInputStream in = new ZipInputStream(Files.newInputStream(file.toPath()))) {
            extZipFileList(in, extPlace);
        }
    }

    /**
     * 解压zip文件到指定目录
     *
     * @param input    要解压缩的文件输入流
     * @param extPlace 目标位置（路径）
     * @throws IOException IO异常
     */
    public static void extZipFileList(final ZipInputStream input, final String extPlace) throws IOException {

        ZipEntry entry;
        while ((entry = input.getNextEntry()) != null) {
            String entryName = entry.getName();
            String fileStr = String.join(File.separator, extPlace, entryName);
            if (entry.isDirectory()) {
                File file = new File(fileStr);
                boolean flag = file.mkdirs();
                input.closeEntry();
                continue;
            }
            try (OutputStream bos = IOUtils.buffer(Files.newOutputStream(Paths.get(fileStr)))) {
                IOUtils.copy(input, bos, 4096);
            }
            input.closeEntry();

        }
    }

    /**
     * 解压（apache tools zip）
     *
     * @param file     要解压缩的文件
     * @param extPlace 目标位置（路径）
     * @throws IOException IO异常
     */
    public static void unZip(final File file, final String extPlace) throws IOException {
        @Cleanup
        ZipFile zipFile = new ZipFile(file);
        File dir = new File(extPlace);
        if (!dir.exists()) {
            boolean flag = dir.mkdirs();
        }
        Enumeration<?> enums = zipFile.getEntries();
        while (enums.hasMoreElements()) {
            org.apache.tools.zip.ZipEntry entry = (org.apache.tools.zip.ZipEntry) enums.nextElement();
            String fileStr = String.join(File.separator, extPlace, entry.getName());
            if (entry.isDirectory()) {// 是目录
                File subDir = new File(fileStr);
                if (!subDir.exists()) {
                    boolean flag = subDir.mkdirs();
                }
                continue;
            }
            // 是文件

            File tmpFile = new File(fileStr);
            File subDir = new File(fileStr).getParentFile();
            if (!subDir.exists()) {
                boolean flag = subDir.mkdirs();
            }
            try (InputStream bis = IOUtils.buffer(zipFile.getInputStream(entry));
                 OutputStream bos = IOUtils.buffer(Files.newOutputStream(tmpFile.toPath()))) {
                IOUtils.copy(bis, bos, 4096);
            }
        }
    }
}
